home *** CD-ROM | disk | FTP | other *** search
- /* mkntfs - create NTFS format filesystems on block devices
- Copyright 1999 by Steve Dodd <dirk@loth.demon.co.uk>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of version 2 of the GNU General Public License as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See version 2
- of the GNU General Public License for more details.
-
- You should have received a copy of version 2 of the GNU General
- Public License along with this program; if not, write to the
- Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
- MA 02139, USA.
-
- Version: $Id: mkntfs.c,v 1.1.1.1 2001/02/11 16:12:51 kmaster Exp $
- */
-
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
-
- #include <stdio.h>
- #include <ctype.h>
- #ifdef HAVE_GETOPT_H
- #include <getopt.h>
- #else
- #define getopt_long(a,v,o,ol,x) getopt(a,v,o)
- #endif
- #ifdef HAVE_UNISTD_H
- #include <unistd.h>
- #endif
- #include <stdlib.h>
- #include <string.h>
- #include <stdarg.h>
-
- #include <fcntl.h>
- #include <errno.h>
-
- #include "ntfstypes.h"
- #include "struct.h"
- #include "macros.h"
- #include "support.h"
- #include "util.h"
- #include "attr.h"
- #include "inode.h"
- #include "super.h"
- #include "dir.h"
- #include "attrtypes.h"
-
- #include <sys/ioctl.h>
- #include <linux/hdreg.h>
- #include <linux/fs.h>
-
- int verbose_flag = 0; /* verbose mode defaults to off */
- int fd; /* file descriptor of block device */
- int cluster_size = 0; /* cluster size in bytes */
- int sector_size = 512; /* sector size in bytes */
- long sect_per_trk = 0; /* sectors per track */
- int heads = 0; /* heads */
- long dev_size; /* size of device in 512 byte blocks */
- long max_lcn; /* largest LCN */
- long mft_lcn = 1; /* LCN of MFT */
- long mftmirr_lcn; /* LCN of MFT mirror */
- int file_rec_size; /* FILE record size in clusters */
- int indx_buf_size; /* index buffer size in clusters */
- char *vol_label=""; /* volume label */
-
- ntfs_volume *vol; /* structure representing volume */
- ntfs_inode *mft_ino; /* inode struct for $MFT */
- ntfs_inode *root_ino; /* inode struct for root */
- ntfs_inode *boot_ino; /* inode struct for $Boot */
-
- void verbose( const char *fmt, ... )
- {
- va_list args;
-
- if( verbose_flag ) {
- va_start( args, fmt );
- vprintf( fmt, args );
- fflush( stdout );
- va_end( args );
- }
- }
-
- void iso8859_2_uni( char *dest, const char *src )
- {
- int i, len;
-
- len = strlen( src );
- for( i = 0; i < len; i++ ) {
- *dest++ = *src++;
- *dest++ = '\0';
- }
- }
-
- void get_blkdev_info( void )
- {
- if( ioctl( fd, BLKGETSIZE, &dev_size ) ) {
- fprintf( stderr, "Couldn't get device size: %s\n",
- strerror( errno ) );
- }
-
- if( !cluster_size ) {
- if( dev_size ) {
- if( dev_size < 512 * 1024 * 2 )
- cluster_size = sector_size;
- else if( dev_size < 1024 * 1024 * 2 )
- cluster_size = 1024;
- else if( dev_size < 2048 * 1024 * 2 )
- cluster_size = 2048;
- else
- cluster_size = 4096;
- } else
- cluster_size = 1024;
- }
-
- if( cluster_size < sector_size )
- cluster_size = sector_size;
-
- printf( "Sector size:\t\t\t%d\n", sector_size );
- printf( "Cluster size:\t\t\t%d\n", cluster_size );
-
- if( cluster_size > 4096 )
- printf( "Warning: large cluster sizes may cause problems with
- compression.\n" );
-
- printf( "Device size:\t\t\t%ld sectors (%ld clusters)\n", dev_size
- * ( sector_size / 512 ), dev_size *
- ( cluster_size / 512 ) );
-
- file_rec_size = max( 1024 / cluster_size, 1 );
- printf( "FILE record size:\t\t%d clusters (%ld bytes)\n", file_rec_size,
- (long)file_rec_size * (long)cluster_size );
-
- indx_buf_size = max( 2048 / cluster_size, 1 );
- verbose( "INDX buffer size:\t\t%d clusters (%ld bytes)\n", indx_buf_size,
- (long)indx_buf_size * (long)cluster_size );
-
- max_lcn = ( dev_size / ( cluster_size / 512 ) ) - 1;
- verbose( "Maximum cluster number:\t\t%ld\n", max_lcn );
-
- printf( "MFT starts at cluster:\t\t%ld\n", mft_lcn );
-
- mftmirr_lcn = max_lcn - ( file_rec_size * 4 ) + 1;
- printf( "Mirror of MFT at cluster:\t%ld\n", mftmirr_lcn );
-
- printf( "\n" );
- }
-
- ntfs_inode *add_mft_entry( int ino )
- {
- char *mftent;
- ntfs_inode *new_ino;
-
- /* allocate mem for MFT entry */
- mftent = calloc( file_rec_size, cluster_size );
- ntfs_fill_mft_header( (ntfs_u8 *)mftent, file_rec_size * cluster_size,
- cluster_size, 0 );
-
- /* insert fix ups */
- ntfs_insert_fixups( (unsigned char *)mftent, sector_size );
-
- /* move to correct position in MFT */
- lseek( fd, ( mft_lcn * cluster_size ) + ( ino * file_rec_size *
- cluster_size ), SEEK_SET );
-
- /* write it */
- write( fd, mftent, file_rec_size * cluster_size );
-
- free( mftent );
-
- /* read it back */
-
- new_ino = (ntfs_inode *)ntfs_malloc( sizeof( ntfs_inode ) );
- ntfs_init_inode( new_ino, vol, ino );
-
- return new_ino;
- }
-
-
- void add_boot_file( void )
- {
- ntfs_attribute *attr;
- ntfs_runlist *rl;
-
- boot_ino = add_mft_entry( FILE_BOOT );
-
- ntfs_create_attr( boot_ino, ATTR_DATA, NULL, NULL, 0, &attr );
- rl = ntfs_malloc( sizeof( ntfs_runlist ) );
-
- attr->resident = 0;
- attr->allocated = attr->initialized = attr->size = 1 * cluster_size;
- rl->len = 1;
- rl->cluster = 0; /* boot cluster at LCN 0 */
- attr->d.r.runlist = rl; attr->d.r.len = 1;
-
- /* flush to disk */
- verbose( "Writing MFT entry for $Boot (%d)...", FILE_BOOT );
- ntfs_update_inode( boot_ino );
- verbose( "done.\n" );
- }
-
- ntfs_attribute *create_name_attr( char *name, int hidden )
- {
- ntfs_attribute *attr;
- char *data;
-
- attr = calloc( sizeof( ntfs_attribute ), 1 );
- data = calloc( 0x42 + strlen( name ) * 2, 1 );
- attr->d.data = data; attr->size = 0x42 + strlen( name ) * 2;
- iso8859_2_uni( data+0x42, name );
- NTFS_PUTU8( data + 0x40, strlen( name ) ); /* file name len */
- NTFS_PUTU8( data + 0x41, 0 ); /* POSIX name space */
- NTFS_PUTU64( data + 0x38, 0x20 |
- ( hidden ? 0x02 : 0 ) ); /* Arch + maybe hidden */
- /* times */
- NTFS_PUTU64( data + 0x8, ntfs_unixutc2ntutc( time( NULL ) ) );
- NTFS_PUTU64( data + 0x10, ntfs_unixutc2ntutc( time( NULL ) ) );
- NTFS_PUTU64( data + 0x18, ntfs_unixutc2ntutc( time( NULL ) ) );
- NTFS_PUTU64( data + 0x20, ntfs_unixutc2ntutc( time( NULL ) ) );
-
- return attr;
- }
-
- void dispose_temp_name( ntfs_attribute *attr )
- {
- free( attr->d.data );
- free( attr );
- }
-
- void add_root_ent( char *name, ntfs_inode *ino )
- {
- ntfs_attribute *attr = create_name_attr( name, 1 );
-
- verbose( "Adding root entry `%s' for inode %d...", name, ino->i_number );
-
- ntfs_dir_add( root_ino, ino, attr );
-
- ntfs_update_inode( root_ino );
-
- dispose_temp_name( attr );
- verbose( "done.\n" );
- }
-
- void init_volume( void )
- {
- ntfs_attribute *attr;
- ntfs_inode *vol_ino;
- char *vol_label_uni;
- char vol_info[0xb];
-
- vol_ino = add_mft_entry( FILE_VOLUME );
-
- /* add volume label */
- vol_label_uni = malloc( strlen( vol_label ) * 2 );
- iso8859_2_uni( vol_label_uni, vol_label );
- ntfs_create_attr( vol_ino, ATTR_VOLUME_NAME, NULL, vol_label_uni,
- strlen( vol_label ) * 2, &attr );
-
- /* add volume information */
- ntfs_create_attr( vol_ino, ATTR_VOLUME_INFORMATION, NULL, vol_info,
- 0xb, &attr );
-
- ntfs_update_inode( vol_ino );
- add_root_ent( "$Volume", vol_ino );
-
- free( vol_label_uni );
- free( vol_ino );
- }
-
- struct attrdef {
- const char *label;
- ntfs_u64 type, flags;
- ntfs_u64 min_size, max_size;
- };
-
- struct attrdef attrdefs[] = {
- { "$STANDARD_INFORMATION", ATTR_STANDARD_INFORMATION, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$ATTRIBUTE_LIST", ATTR_ATTRIBUTE_LIST, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$FILE_NAME", ATTR_FILE_NAME, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
- ASIZE_MIN, ASIZE_MAX },
- { "$VOLUME_VERSION", ATTR_VOLUME_VERSION, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$SECURITY_DESCRIPTOR", ATTR_SECURITY_DESCRIPTOR, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$VOLUME_NAME", ATTR_VOLUME_NAME, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
- ASIZE_MIN, ASIZE_MAX },
- { "$VOLUME_INFORMATION", ATTR_VOLUME_INFORMATION, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$DATA", ATTR_DATA, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
- ASIZE_MAX} ,
- { "$INDEX_ROOT", ATTR_INDEX_ROOT, AFLAG_INDEXABLE | AFLAG_NONRESIDENT,
- ASIZE_MIN, ASIZE_MAX },
- { "$INDEX_ALLOCATION", ATTR_INDEX_ALLOCATION, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$BITMAP", ATTR_BITMAP, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
- ASIZE_MAX },
- { "$SYMBOLIC_LINK", ATTR_SYMBOLIC_LINK, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$EA_INFORMATION", ATTR_EA_INFORMATION, AFLAG_INDEXABLE |
- AFLAG_NONRESIDENT, ASIZE_MIN, ASIZE_MAX },
- { "$EA", ATTR_EA, AFLAG_INDEXABLE | AFLAG_NONRESIDENT, ASIZE_MIN,
- ASIZE_MAX }
- };
-
- int num_attrdefs = sizeof( attrdefs ) / sizeof( struct attrdef );
-
- void init_attrdef( void )
- {
- ntfs_attribute *attr;
- ntfs_inode *attr_ino;
- char *attr_rec;
- int i;
- ntfs_io io;
-
- attr_ino = add_mft_entry( FILE_ATTRDEF );
- ntfs_create_attr( attr_ino, ATTR_DATA, NULL, NULL, 0, &attr );
-
- /* we seem to need to do this before adding data to the inode?
- do we still need to do it after we finish writing the data? */
- ntfs_update_inode( attr_ino );
-
- attr_rec = malloc( 0xa0 );
- io.fn_get = ntfs_get; io.fn_put = ntfs_put;
-
- for( i = 0; i < num_attrdefs; i++ ) {
-
- /* probably not needed, but filesystem dumps are easier to
- read if unused space isn't full of crap */
- memset( attr_rec, 0, 0xa0 );
-
- iso8859_2_uni( attr_rec, attrdefs[i].label );
- NTFS_PUTU16( attr_rec + strlen( attrdefs[i].label )
- * 2, 0x0000 ); /* null-terminate */
-
- NTFS_PUTU64( attr_rec + 0x80, attrdefs[i].type );
- NTFS_PUTU64( attr_rec + 0x88, attrdefs[i].flags );
- NTFS_PUTU64( attr_rec + 0x90, attrdefs[i].min_size );
- NTFS_PUTU64( attr_rec + 0x98, attrdefs[i].max_size );
-
- io.size = 0xa0; io.param = attr_rec;
-
- verbose( "Adding attribute `%s', type 0x%Lx, flags 0x%Lx...",
- attrdefs[i].label, attrdefs[i].type, attrdefs[i].flags );
-
- ntfs_write_attr( attr_ino, ATTR_DATA, NULL, i * 0xa0, &io );
- verbose( "done.\n" );
- }
-
- ntfs_update_inode( attr_ino );
- add_root_ent( "$AttrDef", attr_ino );
- free( attr_rec );
- free( attr_ino );
- }
-
- void init_mftmirr( void )
- {
- ntfs_attribute *attr;
- ntfs_inode *mirr_ino;
- char *mirror_data;
- ntfs_io io;
- ntfs_runlist rl;
-
- mirr_ino = add_mft_entry( FILE_MFTMIRR );
- ntfs_create_attr( mirr_ino, ATTR_DATA, NULL, NULL, 0, &attr );
-
- /* force attribute to allocated area */
-
- attr->resident = 0; attr->allocated = cluster_size * file_rec_size * 4;
- attr->size = attr->initialized = 0; attr->d.r.runlist = &rl;
- attr->d.r.len = 1;
- rl.cluster = mftmirr_lcn; rl.len = attr->allocated / cluster_size;
- ntfs_update_inode( mirr_ino );
-
- /* read critical MFT entries and write to MFTMirr */
-
- mirror_data = malloc( attr->allocated );
- io.size = attr->allocated;
- io.param = mirror_data; io.fn_get = ntfs_get; io.fn_put = ntfs_put;
- ntfs_read_attr( mft_ino, ATTR_DATA, NULL, 0, &io );
- io.param = mirror_data;
- ntfs_write_attr( mirr_ino, ATTR_DATA, NULL, 0, &io );
- free( mirror_data );
-
- ntfs_update_inode( mirr_ino );
- add_root_ent( "$MFTMirr", mirr_ino );
- free( mirr_ino );
- }
-
- void init_empty( char *name, int inum )
- {
- ntfs_attribute *attr;
- ntfs_inode *ino;
-
- ino = add_mft_entry( inum );
- ntfs_create_attr( ino, ATTR_DATA, NULL, NULL, 0, &attr );
- ntfs_update_inode( ino );
- add_root_ent( name, ino );
- free( ino );
- }
-
- void init_root( void )
- {
- /* make new MFT record */
- root_ino = add_mft_entry( FILE_ROOT );
-
- /* do dir stuff */
- root_ino->attr[0x16] |= 2; /* is directory */
- ntfs_add_index_root( root_ino, ATTR_FILE_NAME );
-
- /* flush to disk */
- verbose( "Adding root directory (indexed on type 0x%x, inode %d)...",
- ATTR_FILE_NAME, FILE_ROOT );
- ntfs_update_inode( root_ino );
- verbose( "done.\n" );
-
- /* add entries */
- add_root_ent( ".", root_ino );
- add_root_ent( "$MFT", mft_ino );
- add_root_ent( "$Boot", boot_ino );
- }
-
-
- void init_bitmap( void )
- {
- ntfs_attribute *attr;
- ntfs_inode *bitmap_ino;
- long dev_clusters;
- ntfs_runlist *rl;
- ntfs_cluster_t location; /* these two for ntfs_alloc_clust */
- int count;
-
- /* make new MFT record */
- bitmap_ino = add_mft_entry( FILE_BITMAP );
-
- /* create the attribute */
-
- ntfs_create_attr( bitmap_ino, ATTR_DATA, NULL, NULL, 0, &attr );
- dev_clusters = dev_size / ( cluster_size / 512 ); /* num clusters */
-
- verbose( "%ld clusters on device, %ld bytes wasted.\n",
- dev_clusters, ( dev_size - ( dev_clusters * ( cluster_size /
- 512 ) ) ) * 512 );
-
- attr->resident = 0;
- attr->initialized = attr->size = ( dev_clusters + 7 ) / 8;
- attr->allocated = ( ( attr->size + cluster_size - 1 ) / cluster_size )
- * cluster_size;
- rl = ntfs_malloc( sizeof( ntfs_runlist ) );
- rl->len = attr->allocated / cluster_size;
- rl->cluster = mftmirr_lcn - rl->len; /* bitmap before MFT mirror */
- attr->d.r.runlist = rl; attr->d.r.len = 1;
-
- verbose( "Allocated %d clusters (%d bytes) for bitmap at LCN %d\n",
- rl->len, attr->allocated, rl->cluster );
-
- /* flush to disk */
- ntfs_update_inode( bitmap_ino );
-
- /* now we have a bitmap inode, update struct */
- vol->bitmap = bitmap_ino;
-
- /* clear bitmap */
- ntfs_deallocate_clusters( vol, 0, dev_clusters );
-
- /* allocate cluster ranges we've used already */
-
- location = 0; count = 1; /* boot cluster */
- ntfs_allocate_clusters( vol, &location, &count, ALLOC_REQUIRE_LOCATION |
- ALLOC_REQUIRE_SIZE );
-
- location = mft_lcn; count = 0x10 * file_rec_size; /* MFT */
- ntfs_allocate_clusters( vol, &location, &count,
- ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
-
- location = mftmirr_lcn - rl->len; count = rl->len; /* bmap */
- ntfs_allocate_clusters( vol, &location, &count,
- ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
-
- location = mftmirr_lcn; count = file_rec_size * 4; /* MFT mirror */
- ntfs_allocate_clusters( vol, &location, &count,
- ALLOC_REQUIRE_LOCATION | ALLOC_REQUIRE_SIZE );
-
-
- add_root_ent( "$Bitmap", vol->bitmap );
- }
-
- int write_empty_mft( void )
- {
- char *mftent;
- int rc;
- int attr_off;
- char *attrs, *rl;
- char mftbmap[2] = { 0xff, 0xff };
- ntfs_attribute *attr;
- int i;
- ntfs_io io;
-
- mftent = calloc( file_rec_size, cluster_size );
-
- /* initialise MFT entry 0 */
-
- ntfs_fill_mft_header( (ntfs_u8 *)mftent, file_rec_size * cluster_size,
- cluster_size, 0 );
- attr_off = NTFS_GETU16( mftent+0x14 ); /* offset of attribs */
- attrs = mftent + attr_off; /* location of attrs */
-
- /* insert $DATA attribute */
- /* all this palaver is probably not needed - can we just leap in and
- call Martin's routines straight away? */
-
- NTFS_PUTU32( attrs, ATTR_DATA ); /* type */
- NTFS_PUTU32( attrs + 0x4, 0x49 ); /* length */
- NTFS_PUTU8( attrs + 0x8, 0x01 ); /* not resident */
- NTFS_PUTU8( attrs + 0x9, 0x00 ); /* name len = 0 */
- NTFS_PUTU16( attrs + 0xA, 0x40 ); /* offset to content */
- NTFS_PUTU16( attrs + 0xC, 0x0000 ); /* not compressed */
- NTFS_PUTU16( attrs + 0xE, 0x0000 ); /* huh? */
- NTFS_PUTU64( attrs + 0x10, 0x0 ); /* starting VCN */
- NTFS_PUTU64( attrs + 0x18, 0x0 ); /* ending VCN */
- NTFS_PUTU16( attrs + 0x20, 0x40 ); /* offset to run list */
- NTFS_PUTU16( attrs + 0x22, 0x0000 ); /* no cengine */
- NTFS_PUTU64( attrs + 0x28, 0x10 * file_rec_size *
- cluster_size ); /* we contain 16 file rec */
- NTFS_PUTU64( attrs + 0x30, 0x10 * file_rec_size *
- cluster_size ); /* real size as above */
- NTFS_PUTU64( attrs + 0x38, 0x10 * file_rec_size *
- cluster_size ); /* init size as above */
-
- verbose( "Initial MFT size is 16 records (%d clusters, %d bytes)\n",
- 0x10 * file_rec_size, 0x10 * file_rec_size * cluster_size );
-
- /* name + run list start at 0x40 from attr start */
- rl = attrs + 0x40;
- NTFS_PUTU8( rl, 0x44 ); /* sizeof(off,len)=4 */
- NTFS_PUTU32( rl + 0x1, 0x10 * file_rec_size );
- NTFS_PUTU32( rl + 0x5, mft_lcn ); /* 1st LCN of run */
-
- attrs = rl + 0x09;
-
- verbose( "$MFT data attribute (type 0x%x) run at LCN %d, length %d\n",
- ATTR_DATA, mft_lcn, 0x10 * file_rec_size );
-
- /* mark end of attribs */
- NTFS_PUTU32( attrs, 0xffffffff );
-
- ntfs_insert_fixups( (unsigned char*)mftent, sector_size );
-
- verbose( "Writing bootstrap MFT entry... " );
-
- lseek( fd, mft_lcn * cluster_size, SEEK_SET );
- write( fd, mftent, file_rec_size * cluster_size );
-
- verbose( "done.\n" );
-
-
- /* now things are initialised enough to hand over to Martin's
- routines - phew */
-
- vol->mft = mftent;
- mft_ino = (ntfs_inode *)ntfs_malloc( sizeof( ntfs_inode ) );
- rc = ntfs_init_inode( mft_ino, vol, FILE_MFT );
- vol->mft_ino = mft_ino;
- if( rc ) {
- fprintf( stderr, "Couldn't init inode for $MFT: %s\n",
- strerror( rc ) );
- return rc;
- }
-
-
- /* insert the bitmap attribute */
- ntfs_create_attr( mft_ino, ATTR_BITMAP, NULL, &mftbmap, 2, &attr );
-
- /* write out null MFT entries for slots 1-15 */
- verbose( "Writing 15 (0xf) empty MFT entries " );
- for( i = 1; i < 16; i++ ) {
- ntfs_fill_mft_header( (ntfs_u8 *)mftent,
- file_rec_size * cluster_size, cluster_size, 0 );
- io.fn_get = ntfs_get; io.fn_put = ntfs_put;
- io.size = file_rec_size * cluster_size;
- io.param = mftent;
- ntfs_write_attr( mft_ino, ATTR_DATA, NULL, file_rec_size *
- cluster_size * i, &io );
- verbose( "." );
- }
- verbose( " done.\n" );
-
- /* commit MFT entry */
- verbose( "Flushing MFT info to disk... " );
- ntfs_update_inode( mft_ino );
- verbose( "done\n" );
-
- return 0;
- }
-
-
- void write_boot( void )
- {
- char *bootblk;
-
- bootblk = calloc( cluster_size, 1 );
-
- NTFS_PUTU32( bootblk+3, *(int *)"NTFS" ); /* signature */
- NTFS_PUTU16( bootblk+0xb, sector_size ); /* sector size */
- NTFS_PUTU8( bootblk+0xd, cluster_size / /* sectors per cluster */
- sector_size );
- NTFS_PUTU8( bootblk+0x15, 0xf8 ); /* media descriptor */
- NTFS_PUTU16( bootblk+0x18, sect_per_trk ); /* sectors per track */
- NTFS_PUTU16( bootblk+0x1a, heads ); /* no. of heads */
- NTFS_PUTU16( bootblk+0x24, 0x0080 ); /* ??? */
- NTFS_PUTU16( bootblk+0x26, 0x0080 ); /* ??? */
- NTFS_PUTU64( bootblk+0x28, dev_size *
- ( sector_size / 512 ) ); /* device size (sectors) */
- NTFS_PUTU64( bootblk+0x30, mft_lcn ); /* LCN of MFT */
- NTFS_PUTU64( bootblk+0x38, mftmirr_lcn ); /* LCN of mirror of MFT */
- NTFS_PUTU32( bootblk+0x40, file_rec_size ); /* len of FILE record */
- NTFS_PUTU32( bootblk+0x44, indx_buf_size ); /* len of INDX buffer */
- NTFS_PUTU32( bootblk+0x48, 0x0f000f00 ); /* volume serial num */
- NTFS_PUTU16( bootblk+0x1fe, 0xaa55 ); /* boot sector magic */
-
- /* copy to end of boot cluster */
- if( cluster_size - 0x200 >= 0x200 ) {
- memcpy( bootblk + cluster_size - 0x200, bootblk, 0x200 );
- verbose( "Boot block info duplicated at offset 0x%x\n",
- cluster_size - 0x200 );
- }
-
- verbose( "Writing boot block... " );
-
- lseek( fd, 0, SEEK_SET ); /* seek to cluster 0 */
- write( fd, bootblk, cluster_size );
-
- verbose( "done.\n" );
-
- /* init volume info */
- vol = (ntfs_volume *)ntfs_malloc( sizeof( ntfs_volume ) );
- ntfs_init_volume( vol, bootblk );
- NTFS_FD(vol) = fd;
-
- free( bootblk );
- }
-
- char *short_opts="hVs:u:t:H:n:cvl:";
- #ifdef HAVE_GETOPT_H
- struct option options[]={
- {"help",0,0,'h'},
- {"version",0,0,'V'},
- {"sectsize",1,0,'s'},
- {"clustersize",1,0,'u'},
- {"tracksize",1,0,'t'},
- {"heads",1,0,'H'},
- {"label",1,0,'n'},
- {0,0,0,0}
- };
- #endif
-
- static char const rcsid[] = "$Id: mkntfs.c,v 1.1.1.1 2001/02/11 16:12:51 kmaster Exp $";
-
- char usage_str[]=
- "\nmkntfs " NTFS_VERSION "\n"
- "Usage: mkntfs [-cv] [-s sectsize] [-u clustersize] [-t sectors] [-H heads] \\\n"
- " [-n label] [-l filename] device\n"
- " mkntfs [-hV]\n"
- " --sectsize, -s <n>\t\tSector size of media, default 512\n"
- " --clustersize, -u <n>\t\tCluster size of new filesystem, default varies\n"
- " --tracksize, -t <n>\t\tSectors per track, no default\n"
- " --heads, -H <n>\t\tNumber of heads, no default\n"
- " --label, -n <s>\t\tVolume label, no default\n"
- " -c\t\t\t\tCheck the device for bad blocks first\n"
- " -v\t\t\t\tVerbose output\n"
- " -l <s>\t\t\tFile from which to read list of bad blocks\n"
- " --help, -h\t\t\tDisplay this message\n"
- " --version, -V\t\t\tDisplay version number\n"
- "\n"
- ;
-
-
- void usage(void)
- {
- fprintf(stderr,usage_str);
- }
-
- int main(int argc,char *argv[])
- {
- int c;
- char *device=0;
-
- opterr=1;
- while((c=getopt_long(argc,argv,short_opts,options,NULL))>0)
- switch(c) {
- case 'u': cluster_size=strtol(optarg,NULL,0);break;
- case 's': sector_size=strtol(optarg,NULL,0);break;
- case 't': sect_per_trk=strtol(optarg,NULL,0);break;
- case 'n': vol_label=optarg;break;
- case 'h': usage();exit(0);break;
- case 'V': printf("mkntfs " NTFS_VERSION "\n\t%s\n",rcsid);exit(0);break;
- case 'c':
- case 'l':
- fprintf( stderr, "Sorry -c and -l not yet supported.\n" );
- exit(1);
- break;
- case 'v': verbose_flag = 1; break;
- default: usage();exit(1);
- }
-
- if( argc - optind != 1 ) {
- usage(); exit(1);
- }
-
- device=argv[optind];
-
- fd = open( device, O_RDWR );
- if( fd == -1 ) {
- fprintf( stderr, "Couldn't open %s: %s\n", device,
- strerror(errno) );
- exit( 2 );
- }
-
- printf( "\n" );
-
- get_blkdev_info(); /* get device info, calculate `things' */
- write_boot(); /* write boot cluster based on above info */
- write_empty_mft(); /* initialise the MFT */
- add_boot_file(); /* add an MFT record for the boot cluster */
-
- init_root(); /* initialise the root directory */
- init_bitmap(); /* initialise the volume bitmap */
- init_volume(); /* initialise the volume info */
- init_attrdef(); /* initialise attribute list */
-
- init_empty( "$LogFile", FILE_LOGFILE );
- init_empty( "$BadClus", FILE_BADCLUS );
- init_empty( "$Quota", FILE_QUOTA );
- init_empty( "$UpCase", FILE_UPCASE );
-
- init_mftmirr(); /* make copy of important MFT records:
- do this last */
-
- close( fd );
-
- free( mft_ino );
- free( vol->mft );
- free( vol );
-
- verbose( "\n" );
-
- return 0;
- }
-